package me.chyxion.dao.mybatis;

import java.net.URL;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

/**
 * SqlSessionFactoryBean Extended, 
 * Supports p:typeAliasesPackage="com.foo.bar.**.models" 
 * @version 0.0.1
 * @author Shaun Chyxion <br />
 * chyxion@163.com <br />
 * Jul 12, 2014 3:36:13 PM
 */
public class SqlSessionFactoryBeanExt extends SqlSessionFactoryBean {
	private static final Logger log = LoggerFactory.getLogger(SqlSessionFactoryBeanExt.class);

	@Override
	public void setTypeAliasesPackage(String typeAliasesPackages) {
		log.debug("Parse Type Aliases Packages [{}]", typeAliasesPackages);
		try {
			List<String> classesPaths = new LinkedList<String>();
			// Get root classes paths
	        Enumeration<URL> classesPathURLs = getClass().getClassLoader().getResources("");
	        while (classesPathURLs.hasMoreElements()) {
	            classesPaths.add(classesPathURLs.nextElement().getPath());
            }
	        List<String> pkgs = new LinkedList<String>();
	        PathMatchingResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
	        for (String pkg : StringUtils.tokenizeToStringArray(typeAliasesPackages, 
	        					ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)) {
	        	log.debug("Parse Type Aliases Package [{}]", pkg);
	        	for (Resource pkgResource : resourceResolver.getResources(
	        				ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + 
	        					ClassUtils.convertClassNameToResourcePath(pkg))) {
	        		String pkgPath = pkgResource.getURL().getPath();
	        		log.debug("Found Type Aliases Package [{}]", pkgPath);
	        		for (String classesPath : classesPaths) {
	        			if (pkgPath.startsWith(classesPath)) {
	        				log.debug("Found Type Aliases Package [{}] In Class Path [{}]", pkgPath, classesPath);
	        				// Remove root classes path
	        				pkgPath = pkgPath.replace(classesPath, "");
	        				// Trim last /
	        				if (pkgPath.endsWith("/")) {
	        					pkgPath = pkgPath.substring(0, pkgPath.length() - 1);
	        				}
	        				// Convert path to package
	        				pkgPath = pkgPath.replace('/', '.');
	        				log.debug("Parse Type Aliases Package Result [{}]", pkgPath);
	        				pkgs.add(pkgPath);
	        				break;
	        			}
                    }
	        	}
	        }
	        super.setTypeAliasesPackage(org.apache.commons.lang3.StringUtils.join(pkgs, ", "));
        } 
		catch (Exception e) {
			log.warn("Parse Type Aliases Package ERROR. {}", e);
			throw new RuntimeException("Parse Type Aliases Packages ERROR.", e);
        }
	}
}
